package net.ufrog.common.utils;

import net.ufrog.common.CoreConfig;
import net.ufrog.common.Logger;
import net.ufrog.common.utils.Cryptos.HashType;
import org.apache.commons.codec.DecoderException;
import org.apache.commons.codec.binary.Hex;

import java.security.SecureRandom;

/**
 * 密码工具类
 * 
 * @author ultrafrog
 * @version 1.0, 2014-09-27
 * @since 1.0
 */
public class Passwords {

    private static SecureRandom secureRandom = new SecureRandom();

    /** 构造函数 */
    private Passwords() {}

    /**
     * 密码加密
     *
     * @param str 待加密字符串
     * @return 加密字符串
     */
    public static String encode(String str) {
        byte[] salt = new byte[8];
        secureRandom.nextBytes(salt);
        return encode(str, salt);
    }

    /**
     * 密码匹配
     *
     * @param raw 原始密码
     * @param encoded 加密密码
     * @return 匹配结果
     */
    public static Boolean match(String raw, String encoded) {
        try {
            byte[] digest = Hex.decodeHex(encoded.toCharArray());
            byte[] salt = sub(digest, 0, 8);
            return Strings.equals(encoded, encode(raw, salt));
        } catch (DecoderException e) {
            Logger.warn(e.getMessage());
            return Boolean.FALSE;
        }
    }

    /**
     * 加密
     *
     * @param str 待加密字符串
     * @param salt 盐
     * @return 加密结果
     */
    private static String encode(String str, byte[] salt) {
        byte[] digest = Cryptos.hash(concatenate(salt, str.getBytes(CoreConfig.getCharset())), HashType.SHA256);
        return new String(Hex.encodeHex(concatenate(salt, digest)));
    }

    /**
     * 合并字节数组
     *
     * @param arrays 字节数组
     * @return 字节数组
     */
    private static byte[] concatenate(byte[]... arrays) {
        Integer length = 0;
        for (byte[] array: arrays) length += array.length;

        Integer destpos = 0;
        byte[] dest = new byte[length];
        for (byte[] array: arrays) {
            System.arraycopy(array, 0, dest, destpos, array.length);
            destpos += array.length;
        }
        return dest;
    }

    /**
     * 部分字节数组
     *
     * @param array 字节数组
     * @param beginIndex 开始位置
     * @param endIndex 结束位置
     * @return 部分字节数组
     */
    private static byte[] sub(byte[] array, Integer beginIndex, Integer endIndex) {
        Integer length = endIndex - beginIndex;
        byte[] sub = new byte[length];
        System.arraycopy(array, beginIndex, sub, 0, length);
        return sub;
    }
}
